﻿//  Copyright (c) 2010 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web;
using System.Web.UI;
using System.Xml;
using System.IO;
using System.Web.WebPages;

namespace DNA.Mvc.jQuery
{
    public class TreeViewBuilder : jQueryHierarchicalComponentBuilder<TreeOptions, TreeView, TreeNode, TreeNodeFactory, TreeViewBuilder>
    {
        private string _key;
        private string _val;
        // private string _url;
        //private Action _jQueryTmpl;
        //private Func<object, object> _jQueryInlineTmpl;
        //private string _httpMethod = "POST";

        protected override string jQueryPluginName
        {
            get { return "dtree"; }
        }

        public TreeViewBuilder(TreeView treeview, ViewContext viewContext, IViewDataContainer viewContainer) : base(treeview, viewContext, viewContainer) { }

        protected override TreeNodeFactory CreateNodeItemFactory()
        {
            return new TreeNodeFactory(Component, this.ViewContext, this.ViewDataContainer) { NodeContainer = Component };
        }

        protected override HierarchialBindingFactory<TreeNode, TreeView> CreateBindingFactory()
        {
            return new HierarchialBindingFactory<TreeNode, TreeView>(Component, (item) =>
            {
                return new TreeNode(item) { Container = this.Component };
            });
        }

        public TreeViewBuilder DragAndDrop(bool enableDragAndDrop)
        {
            return this.DragAndDrop(enableDragAndDrop, string.Empty);
        }

        public TreeViewBuilder SinglePathExpand(bool selectSingle)
        {
            return Options(opts =>
                {
                    opts.SinglePathExpand = selectSingle;
                });
        }

        public TreeViewBuilder DragAndDrop(bool enableDragAndDrop, string dropTargets)
        {
            return Options(opts =>
            {
                opts.EnableDropAndDrag = enableDragAndDrop;
                if (!string.IsNullOrEmpty(dropTargets))
                    opts.DropTargets = dropTargets;
            });
        }

        public TreeViewBuilder ShowCheckboxs(bool checkboxs)
        {
            return Options(opts =>
            {
                opts.AllowCheckNodes = checkboxs;
            });
        }

        /// <summary>
        /// Load the tree nodes from remote url.
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public TreeViewBuilder ClientBind(string url)
        {
            return this.ClientBind(url, null);
        }

        /// <summary>
        /// Load the tree nodes from remote url.
        /// </summary>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <returns></returns>
        public TreeViewBuilder ClientBind(string url, string httpMethod)
        {
            if (!string.IsNullOrEmpty(httpMethod))
                Component.HttpMethod = httpMethod;
            if (!string.IsNullOrEmpty(url))
                Component.RemoteDataSource = url;
            //_httpMethod = httpMethod;
            return this;
        }

        //public TreeViewBuilder ClientBind(string url, Action clientTemplate)
        //{
        //    return this.ClientBind(url, null, clientTemplate);
        //}

        //public TreeViewBuilder ClientBind(string url, Func<object, object> clientTemplate)
        //{
        //    return this.ClientBind(url, null, clientTemplate);
        //}

        //public TreeViewBuilder ClientBind(string url, string httpMethod, Func<object, object> clientTemplate)
        //{
        //    if (!string.IsNullOrEmpty(url))
        //        Component.RemoteDataSource = url;

        //    if (!string.IsNullOrEmpty(httpMethod))
        //        Component.HttpMethod = httpMethod;

        //    Component.ClientTemplate.InlineContent=clientTemplate;
        //    return this;
        //}

        //public TreeViewBuilder ClientBind(string url, string httpMethod, Action clientTemplate)
        //{
        //    if (!string.IsNullOrEmpty(url))
        //        Component.RemoteDataSource = url;

        //    if (!string.IsNullOrEmpty(httpMethod))
        //        Component.HttpMethod = httpMethod;

        //    Component.ClientTemplate.Content = clientTemplate;
        //    return this;
        //}

        protected void BuildDefaultClientTemplate()
        {
            Options(opts =>
            {
                opts.OnNodePopulate = (new StringBuilder())
                                           .Append("var $n = $(node);")
                                           .Append("$n.addClass(\"d-treenode-loading\");")
                                           .Append("var url = $(\">.d-treenode-content\", $n).find(\".d-treenode-value\").val();")
                                           .Append("$(\"#" + Component.Id + "\").dtree(\"loadNodes\", url, \"" + Component.HttpMethod + "\", {}, $n);")
                                           .Append("$n.removeClass(\"d-treenode-hasChildren\");")
                                           .ToString();
                opts.OnNodeLoaded = "if (node) {$(node).removeClass(\"d-treenode-loading\");}";
            });

            this.ClientNodeTemplate(new Func<object, object>(obj =>
            {
                return new HelperResult(writer =>
                {
                    writer.Write("<li {{if Value}} class=\"d-treenode-hasChildren\" {{/if}} class=\"d-treenode-hasChildren\" >");
                    writer.Write("<a href=\"${NavigateUrl}\" title=\"${ToolTip}\" {{if Target}} target=\"${Target}\" {{/if}} >");
                    writer.Write(" {{if ImageUrl}} ");
                    writer.Write("<img src=\"${ImageUrl}\" class=\"d-treenode-img\" alt=\"${Text}\" />");
                    writer.Write(" {{/if}}");
                    writer.Write("{{if Value}} <input type=\"hidden\" class=\"d-treenode-value\" value=\"${Value}\" /> {{/if}}");
                    writer.Write("<span class=\"d-treenode-text\">${Text}</span></a></li>");
                });
            }
            ));
        }

        /// <summary>
        /// Define the jQuery template for nodes.
        /// </summary>
        /// <param name="nodeTemplate"></param>
        /// <returns></returns>
        public TreeViewBuilder ClientNodeTemplate(Func<object, object> nodeTemplate)
        {
            Component.ClientTemplate.InlineContent = nodeTemplate;
            return this;
        }

        /// <summary>
        /// Define the jQuery template for nodes.
        /// </summary>
        /// <param name="nodeTemplate"></param>
        /// <returns></returns>
        public TreeViewBuilder ClientNodeTemplate(Action nodeTemplate)
        {
            Component.ClientTemplate.Content = nodeTemplate;
            return this;
        }

        public TreeViewBuilder ExpandedLevel(int level)
        {
            Component.ExpandedLevel = level;
            return this;
        }

        public TreeViewBuilder SelectNode(string key, string value)
        {
            _key = key;
            _val = value;
            return this;
        }

        public override void Render()
        {
            if (!string.IsNullOrEmpty(Component.RemoteDataSource))
            {
                using (var writer = new HtmlTextWriter(this.ViewContext.Writer))
                {
                    if (Component.ClientTemplate.IsEmpty)
                        this.BuildDefaultClientTemplate();

                    Options(opts =>
                    {
                        opts.NodeTemplate = Component.Id + "_tmpl";
                    });

                    Component.Render(writer);
                    _RenderStartupScripts();
                }
            }
            else
                base.Render();

            _InitSelection();
        }

        public override MvcHtmlString GetHtml()
        {
            MvcHtmlString result=MvcHtmlString.Empty;

            if (!string.IsNullOrEmpty(Component.RemoteDataSource))
            {
                //var sb = new StringBuilder();

                    if (Component.ClientTemplate.IsEmpty)
                        this.BuildDefaultClientTemplate();

                    Options(opts =>
                    {
                        opts.NodeTemplate = Component.Id + "_tmpl";
                    });

                    //sbComponent.Render(writer);
                    result =MvcHtmlString.Create(Component.GetHtml());
                    _RenderStartupScripts();
            }
            else
                result = base.GetHtml();

            _InitSelection();
            //return base.ToHtml();
            return result;
        }

        private void _RenderStartupScripts()
        {
            //RenderClientTemplate(writer);
            Helper.jQuery(Component.Name, jQueryPluginName, options);
            var firstLoad = new StringBuilder();
            firstLoad.Append(jQuerySelector + ".dtree(\"loadNodes\",\"")
                .Append(Component.RemoteDataSource)
                .Append("\",\"")
                .Append(Component.HttpMethod)
                .Append("\",{});");
            Helper.RegisterStartupScript(firstLoad.ToString());
        }

        private void _InitSelection()
        {
            if (!string.IsNullOrEmpty(_key) && !string.IsNullOrEmpty(_val))
            {
                Helper.RegisterStartupScript(jQuerySelector + ".dtree(\"findNodeElement\",\"" + _key + "\",\"" + _val + "\")");
            }
        }
    }

}
